package com.guet.common.contoller;

import com.guet.common.exception.ApiException;
import com.guet.common.response.ResultCodeEnum;
import com.guet.common.response.ResultVO;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MultipartException;

/**
 * @author dragon
 * 异常通知
 * 当控制层 Controller 中的处理器 Handler 方法发生异常时，会被当前类拦截下来
 */
@RestControllerAdvice
public class ExceptionControllerAdvice {

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ResultVO<String> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        // 从异常对象中拿到 ObjectError 对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        // 然后提取错误提示信息进行返回，getDefaultMessage 返回的是校验注解中定义的message属性值
        String errorMessage = objectError.getDefaultMessage();
        // 返回错误码，并在 data 中存放具体参数校验失败的原因
        return new ResultVO<>(ResultCodeEnum.FAIL_PARAM_VALIDATE, errorMessage);
    }

    @ExceptionHandler({ApiException.class})
    public ResultVO<String> apiExceptionHandler(
            ApiException e) {
        if (e.getCode() != 0) {
            return new ResultVO<>(e.getCode(), e.getMsg(), e.getDetail());
        }
        return new ResultVO<>(ResultCodeEnum.BIZ_FAIL, e.getDetail());
    }

    // Form请求缺少必填参数
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public ResultVO<String> missingServletRequestParameterExceptionHandler(
            MissingServletRequestParameterException e) {
        return new ResultVO<>(ResultCodeEnum.FAIL_PARAM_MISSING, e.getLocalizedMessage());
    }

    // 请求方法不对。例如: 要求POST请求，但执行的是GET请求
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public ResultVO<String> httpRequestMethodNotSupportedExceptionHandler(
            HttpRequestMethodNotSupportedException e) {
        return new ResultVO<>(ResultCodeEnum.FAIL_REQUEST_METHOD, e.getLocalizedMessage());
    }

    // JSON请求内容为空。例如，JSON请求时没有传入JSON内容
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public ResultVO<String> httpMessageNotReadableExceptionHandler(
            HttpMessageNotReadableException e) {
        return new ResultVO<>(ResultCodeEnum.FAIL_REQUEST_CONTENT, e.getLocalizedMessage());
    }

    // Form请求参数类型不匹配。例如：要求参数类型是整型，却传入的是字符串类型
    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    public ResultVO<String> methodArgumentTypeMismatchExceptionHandler(
            MethodArgumentTypeMismatchException e) {
        return new ResultVO<>(ResultCodeEnum.FAIL_PARAM_VALIDATE, e.getLocalizedMessage());
    }

    // 请求内容的类型不匹配。例如：要求请求内容的类型是JSON格式，即Content-Type=application/json;charset=UTF-8。但是，实际类型为Content-Type=application/text;charset=UTF-8。
    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    public ResultVO<String> httpMediaTypeNotSupportedExceptionHandler(
            HttpMediaTypeNotSupportedException e) {
        return new ResultVO<>(ResultCodeEnum.FAIL_REQUEST_TYPE, e.getLocalizedMessage());
    }

    // 请求方式不是文件上传请求方式
    @ExceptionHandler({MultipartException.class})
    public ResultVO<String> multipartExceptionHandler(
            MultipartException e) {
        return new ResultVO<>(ResultCodeEnum.FAIL_REQUEST_METHOD, e.getLocalizedMessage());
    }

    @ExceptionHandler({Exception.class})
    public ResultVO<String> exceptionHandler(Exception e) {
        e.printStackTrace();
        return new ResultVO<>(ResultCodeEnum.BIZ_FAIL, e.getLocalizedMessage());
    }
}
